//
////  add_dylib_demo.m
//
//#import <Foundation/Foundation.h>
//#include <mach-o/loader.h>
//#include <mach-o/swap.h>
//#include <mach-o/fat.h>
////MARK: - 定义一些工具方法
//BOOL isFatOfMagic(uint32 magic) {
//    return magic == FAT_MAGIC || magic == FAT_CIGAM;
//}
//BOOL isMagic64(uint32 magic) {
//    return magic == MH_MAGIC_64 || magic == MH_CIGAM_64;
//}
//BOOL shouldSwapBytesOfMagic(uint32 magic) {
//    return magic == MH_CIGAM || magic == MH_CIGAM_64 || magic == FAT_CIGAM || magic == FAT_CIGAM_64;
//}
//BOOL isValidMachoOfMagic(uint32 magic){
//    return magic == FAT_MAGIC || magic == FAT_CIGAM || magic == MH_MAGIC_64 || magic == MH_CIGAM_64;
//}
//@interface NSFileHandle(Extension)
//- (NSData *)readDataFromOffSet:(unsigned long long)offset length:(NSUInteger)length;
//- (const void *)readBytesFromOffSet:(unsigned long long)offset length:(NSUInteger)length;
//- (void)writeData:(NSData *)data offSet:(unsigned long long)offset;
//- (void)writeBytes:(void *)bytes offSet:(unsigned long long)offSet length:(NSUInteger)length;
//@end
//
//@implementation NSFileHandle(Extension)
//- (NSData *)readDataFromOffSet:(unsigned long long)offset length:(NSUInteger)length{
//    [self seekToFileOffset:offset];
//    return [self readDataOfLength:length];
//}
//- (const void *)readBytesFromOffSet:(unsigned long long)offSet length:(NSUInteger)length{
//    return [[self readDataFromOffSet:offSet length:length] bytes];
//}
//- (void)writeData:(NSData *)data offSet:(unsigned long long)offset{
//    [self seekToFileOffset:offset];
//    [self writeData:data];
//}
//- (void)writeBytes:(void *)bytes offSet:(unsigned long long)offSet length:(NSUInteger)length{
//    NSData * d = [[NSData alloc]initWithBytes:bytes length:length];
//    [self writeData:d offSet: offSet];
//}
//@end
//
////Demo 主逻辑
//int main(int argc, const char * argv[]) {
//  
//    NSString * machoFilePath = @"/Users/jerry/Desktop/testMacho";
//    NSFileHandle * machoFileHandle = [NSFileHandle fileHandleForUpdatingAtPath: machoFilePath];
//    /* 读取魔数（前4个字节）
//     要注意的是，后面还有一个魔数，是MachO部分的，此处是针对 fat_arch 和 fat_header 相关信息的。
//     后面的是用于某个arch下的 MachO 的。
//     */
//    uint32 magic = *((uint32 *)[machoFileHandle readBytesFromOffSet:0 length:4]);
//    //thin 还是 fat 版本
//    BOOL isFat = isFatOfMagic(magic);
//    //是否是64位
//    BOOL is64 = isMagic64(magic);
//    //大小端转换判断
//    BOOL shouldSwap = shouldSwapBytesOfMagic(magic);
//    
//    if(isFat){
//        int fat_header_size = sizeof(struct fat_header);
//        struct fat_header * fatHeader = (struct fat_header *)[machoFileHandle readBytesFromOffSet:0 length:fat_header_size];
//        if (shouldSwap) {
//            swap_fat_header(fatHeader, 0);
//        }
//        int arch_offset = fat_header_size;
//        uint64_t machHeaderOffset = 0;
//        //遍历所有 arch
//        for (int i = 0; i < fatHeader->nfat_arch; i++) {
//            if(is64){
//                int fat_arch_size = sizeof(struct fat_arch_64);
//                struct fat_arch_64 * arch = (struct fat_arch_64 *)[machoFileHandle readBytesFromOffSet:arch_offset length:fat_arch_size];
//                if (shouldSwap) {
//                    //大小端转换
//                    swap_fat_arch_64(arch, 1, 0);
//                }
//                //保存 mach header 的起始位置
//                machHeaderOffset = arch->offset;
//                //计算下个 fat_arch 的位置
//                arch_offset += fat_arch_size;
//            }else{
//                int fat_arch_size = sizeof(struct fat_arch);
//                struct fat_arch * arch = (struct fat_arch *)[machoFileHandle readBytesFromOffSet:arch_offset length:fat_arch_size];
//                if (shouldSwap) {
//                    swap_fat_arch(arch, 1, 0);
//                }
//                machHeaderOffset = arch->offset;
//                arch_offset += fat_arch_size;
//            }
//            //创建要添加的 dylib_command
//            NSString * dylibLinkStr = @"@executable_path/test.dylib";
//            uint32 dylib_size = (uint32)[[dylibLinkStr dataUsingEncoding:NSUTF8StringEncoding] length] + sizeof(struct dylib_command);
//            dylib_size += sizeof(long) - (dylib_size % sizeof(long)); //按 long 类型长度对齐
//            struct dylib_command dyld;
//            dyld.cmd = LC_LOAD_DYLIB;
//            dyld.cmdsize = dylib_size;
//            dyld.dylib.compatibility_version = 0;
//            dyld.dylib.current_version = 0;
//            dyld.dylib.timestamp = 0;
//            dyld.dylib.name.offset = sizeof(struct dylib_command);
//            
//            uint32 machMagic = *((uint32 *)[machoFileHandle readBytesFromOffSet:machHeaderOffset length:4]);
//            BOOL isMach64 = isMagic64(machMagic);
//            BOOL shoudMachSwap = shouldSwapBytesOfMagic(machMagic);
//            int totalCmdSize = 0;
//            int machHeaderSize = 0;
//            if(isMach64){
//                machHeaderSize = sizeof(struct mach_header_64);
//                struct mach_header_64 * header = (struct mach_header_64 *)[machoFileHandle readBytesFromOffSet:machHeaderOffset length: machHeaderSize];
//                if (shoudMachSwap) {
//                    swap_mach_header_64(header, 0);
//                }
//         
//                totalCmdSize = header->sizeofcmds;
//                header->ncmds += 1;
//                header->sizeofcmds += dyld.cmdsize;
//                [machoFileHandle writeBytes: header offSet: machHeaderOffset length: machHeaderSize];
//            }else{
//                machHeaderSize = sizeof(struct mach_header);
//                struct mach_header * header = (struct mach_header *)[machoFileHandle readBytesFromOffSet:machHeaderOffset length: machHeaderSize];
//                if (shoudMachSwap) {
//                    swap_mach_header(header, 0);
//                }
//                totalCmdSize = header->sizeofcmds;
//                header->ncmds += 1;
//                header->sizeofcmds += dyld.cmdsize;
//                [machoFileHandle writeBytes: header offSet: machHeaderOffset length: machHeaderSize];
//            }
//            [machoFileHandle writeBytes: &dyld offSet: machHeaderOffset + machHeaderSize + totalCmdSize length: sizeof(struct dylib_command)];
//            [machoFileHandle writeData: [dylibLinkStr dataUsingEncoding:NSUTF8StringEncoding]];
//        }
//    }else{
//        //thin版本 参考 fat 版本处理流程即可（从 mach_header出开始处理）
//        assert(false);
//    }
//    
//    return 0;
//}
